﻿using System;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Runtime.InteropServices;
using System.IO.Compression;

namespace DataCollector
{
    public partial class DataCollectorForm : Form
    {

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool BackupEventLog(IntPtr hEventLog, string backupFile);

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr OpenEventLog(string lpUNCServerName, string lpSourceName);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool CloseEventLog(IntPtr hEventLog);

        const string metabase = @"C:\windows\system32\inetsrv\metabase.xml";
        const string applicationhost = @"c:\windows\system32\inetsrv\config\applicationHost.config";
        const string httperr = @"C:\Windows\System32\LogFiles\HTTPERR\";

        bool isMetabase = false;

        XmlNodeList nodes;

        public DataCollectorForm()
        {
            InitializeComponent();
            InitializeControls();
        }

        private void InitializeControls()
        {
            IntPtr ptr = new IntPtr();
            bool isWow64FsRedirectionDisabled = Wow64DisableWow64FsRedirection(ref ptr);

            if (File.Exists(applicationhost))
            {
                isMetabase = false;
                string configuration = File.ReadAllText(applicationhost);
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(configuration);
                nodes = doc.SelectNodes("//site");
                foreach (XmlNode node in nodes)
                {
                    string serverName = node.Attributes["name"].Value;
                    lbSites.Items.Add(serverName);
                }
            }
            else if (File.Exists(metabase))
            {
                isMetabase = true;
                string configuration = File.ReadAllText(metabase);
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(configuration);
                XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
                nsmgr.AddNamespace("ns", "urn:microsoft-catalog:XML_Metabase_V64_0");
                nodes = doc.SelectNodes("//ns:IIsWebServer", nsmgr);
                foreach (XmlNode node in nodes)
                {
                    string serverName = node.Attributes["ServerComment"].Value;
                    lbSites.Items.Add(serverName);
                }
            }

            if (isWow64FsRedirectionDisabled)
            {
                Wow64RevertWow64FsRedirection(ptr);
            }
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            if (fdbDest.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtDestFolder.Text = fdbDest.SelectedPath;
            }
        }

        private void btnCollect_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrEmpty(txtDestFolder.Text))
                {
                    txtOutput.Text = "Please choose a destination folder.";
                }
                string path = txtDestFolder.Text.Trim();
                if (!Directory.Exists(path))
                {
                    txtOutput.Text = "Destination folder does not exist.";
                }

                string destPath = path + "\\IISData";
                if (!Directory.Exists(destPath))
                {
                    Directory.CreateDirectory(destPath);
                    txtOutput.Text = string.Format("Created folder {0}\r\n{1}", destPath, txtOutput.Text);
                }

                bool overwrite = cbOverride.Checked;
                DateTime dateSince = dtpSince.Value;
                if (isMetabase)
                {
                    IntPtr ptr = new IntPtr();
                    bool isWow64FsRedirectionDisabled = Wow64DisableWow64FsRedirection(ref ptr);

                    if (cbIISConfig.Checked)
                    {
                        File.Copy(metabase, destPath + "\\metabase.xml", overwrite);
                        txtOutput.Text = string.Format("Copied file metabase.xml\r\n{0}", txtOutput.Text);
                    }

                    if (cbHttpError.Checked)
                    {
                        string httperrDest = destPath + "\\httperr";
                        if (!Directory.Exists(httperrDest))
                        {
                            Directory.CreateDirectory(httperrDest);
                            txtOutput.Text = string.Format("Created folder {0}\r\n", httperrDest, txtOutput.Text);
                        }
                        string[] httplogs = Directory.GetFiles(httperr);
                        foreach (string httplog in httplogs)
                        {
                            if (File.GetLastWriteTime(httplog) >= dateSince)
                            {
                                File.Copy(httplog, httperrDest + "\\" + httplog.Substring(httplog.LastIndexOf("\\")), overwrite);
                                txtOutput.Text = string.Format("Copied file {0}\r\n{1}", httplog, txtOutput.Text);
                            }
                        }
                    }

                    if (cbIISlog.Checked)
                    {
                        foreach (string site in lbSites.SelectedItems)
                        {
                            foreach (XmlNode node in nodes)
                            {
                                if (string.Compare(site, node.Attributes["ServerComment"].Value, true) == 0)
                                {
                                    string iisLogPath = (node.Attributes["LogFileDirectory"] != null ?
                                        node.Attributes["LogFileDirectory"].Value + "\\W3SVC" + node.Attributes["Location"].Value.Substring(node.Attributes["Location"].Value.LastIndexOf("/") + 1) 
                                        : @"C:\WINDOWS\system32\LogFiles\W3SVC" + node.Attributes["Location"].Value.Substring(node.Attributes["Location"].Value.LastIndexOf("/") + 1));

                                    string iislogDest = destPath + "\\iislog\\";
                                    string sitelogDest = iislogDest + node.Attributes["ServerComment"].Value;
                                    if (!Directory.Exists(iislogDest))
                                    {
                                        Directory.CreateDirectory(iislogDest);
                                        txtOutput.Text = string.Format("Created folder {0}\r\n", iislogDest, txtOutput.Text);
                                    }

                                    if (!Directory.Exists(sitelogDest))
                                    {
                                        Directory.CreateDirectory(sitelogDest);
                                        txtOutput.Text = string.Format("Created folder {0}\r\n", sitelogDest, txtOutput.Text);
                                    }

                                    string[] iislogs = Directory.GetFiles(iisLogPath);
                                    foreach (string iislog in iislogs)
                                    {
                                        if (File.GetLastWriteTime(iislog) >= dateSince)
                                        {
                                            File.Copy(iislog, sitelogDest + "\\" + iislog.Substring(iislog.LastIndexOf("\\")), overwrite);
                                            txtOutput.Text = string.Format("Copied file {0}\r\n{1}", iislog, txtOutput.Text);
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                    }

                    if (isWow64FsRedirectionDisabled)
                    {
                        Wow64RevertWow64FsRedirection(ptr);
                    }

                    if (cbEventLog.Checked)
                    {
                        IntPtr appLogHandle = OpenEventLog(null, "Application");
                        BackupEventLog(appLogHandle, destPath + "\\Application.evt");
                        CloseEventLog(appLogHandle);
                        txtOutput.Text = string.Format("Exported application event log\r\n{0}", txtOutput.Text);

                        IntPtr systemLogHandle = OpenEventLog(null, "System");
                        BackupEventLog(systemLogHandle, destPath + "\\System.evt");
                        CloseEventLog(systemLogHandle);
                        txtOutput.Text = string.Format("Exported system event log\r\n{0}", txtOutput.Text);
                    }
                }
                else
                {
                    IntPtr ptr = new IntPtr();
                    bool isWow64FsRedirectionDisabled = Wow64DisableWow64FsRedirection(ref ptr);
                    if (cbIISConfig.Checked)
                    {
                        File.Copy(applicationhost, destPath + "\\applicationhost.config", overwrite);
                        txtOutput.Text = string.Format("Copied file applicationhost.config\r\n{0}", txtOutput.Text);
                    }

                    if (cbHttpError.Checked)
                    {
                        string httperrDest = destPath + "\\httperr";
                        if (!Directory.Exists(httperrDest))
                        {
                            Directory.CreateDirectory(httperrDest);
                            txtOutput.Text = string.Format("Created folder {0}\r\n", httperrDest, txtOutput.Text);
                        }
                        string[] httplogs = Directory.GetFiles(httperr);
                        foreach (string httplog in httplogs)
                        {
                            if (File.GetLastWriteTime(httplog) >= dateSince)
                            {
                                File.Copy(httplog, httperrDest + "\\" + httplog.Substring(httplog.LastIndexOf("\\")), overwrite);
                                txtOutput.Text = string.Format("Copied file {0}\r\n{1}", httplog, txtOutput.Text);
                            }
                        }
                    }

                    if (isWow64FsRedirectionDisabled)
                    {
                        Wow64RevertWow64FsRedirection(ptr);
                    }

                    if (cbIISlog.Checked)
                    {
                        foreach (string site in lbSites.SelectedItems)
                        {
                            foreach (XmlNode node in nodes)
                            {
                                if (string.Compare(site, node.Attributes["name"].Value, true) == 0)
                                {
                                    XmlNode logNode = node.SelectSingleNode("logFile");

                                    string iisLogPath = (logNode != null && logNode.Attributes["directory"] != null ?
                                        logNode.Attributes["directory"].Value + "\\W3SVC" + node.Attributes["id"].Value : @"C:\inetpub\logs\LogFiles\W3SVC" + node.Attributes["id"].Value);

                                    string iislogDest = destPath + "\\iislog\\";
                                    string sitelogDest = iislogDest + node.Attributes["name"].Value;
                                    if (!Directory.Exists(iislogDest))
                                    {
                                        Directory.CreateDirectory(iislogDest);
                                        txtOutput.Text = string.Format("Created folder {0}\r\n", iislogDest, txtOutput.Text);
                                    }

                                    if (!Directory.Exists(sitelogDest))
                                    {
                                        Directory.CreateDirectory(sitelogDest);
                                        txtOutput.Text = string.Format("Created folder {0}\r\n", sitelogDest, txtOutput.Text);
                                    }

                                    string[] iislogs = Directory.GetFiles(iisLogPath);
                                    foreach (string iislog in iislogs)
                                    {
                                        if (File.GetLastWriteTime(iislog) >= dateSince)
                                        {
                                            File.Copy(iislog, sitelogDest + "\\" + iislog.Substring(iislog.LastIndexOf("\\")), overwrite);
                                            txtOutput.Text = string.Format("Copied file {0}\r\n{1}", iislog, txtOutput.Text);
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                    }

                    if (cbEventLog.Checked)
                    {
                        IntPtr appLogHandle = OpenEventLog(null, "Application");
                        BackupEventLog(appLogHandle, destPath + "\\Application.evtx");
                        CloseEventLog(appLogHandle);
                        txtOutput.Text = string.Format("Exported application event log\r\n{0}", txtOutput.Text);

                        IntPtr systemLogHandle = OpenEventLog(null, "System");
                        BackupEventLog(systemLogHandle, destPath + "\\System.evtx");
                        CloseEventLog(systemLogHandle);
                        txtOutput.Text = string.Format("Exported system event log\r\n{0}", txtOutput.Text);
                    }
                }

                txtOutput.Text = string.Format("###########################################\r\nCollection done!\r\n{0}", txtOutput.Text);
            }

            catch (Exception ex)
            {
                txtOutput.Text = string.Format("Exception happened during collection.\r\n{0}\r\n{1}", ex.ToString(), txtOutput.Text);
            }
        }
    }
}
